import { App } from "../../../src/App";
import { Singleton } from "../../../src/core/Class";
import { RedPointEvent } from "../../../src/core/EventConst";
import PropSys, { PropAttribute, PropType } from "./PropSys";
import RedPointSys from "./RedPointSys";

const MAX_CONTAINERS:number = 50; // 背包容器(即最大可容纳物品数量)
const INFINITE:number = 10e20; // 叠加最大上限

interface Item{
    id:number,
    count:number,
}

// 道具使用结果
enum UsePropResult{
    unknow=-1,
    success,
    fail
}

class CPackSys extends Singleton<CPackSys> {
    private _items:Item[] = [];
    protected onInit(){
    }

    protected onDestroy(){
        this._items = [];
        cc.log('destroy pack system end.');
    }

    public updatePack(){
        if (App.getCfg('test')){
            this._items.push({id:200001,count:3});
            this._items.push({id:400000,count:10});
            this._items.push({id:500000,count:3});
            this._items.push({id:300000,count:3});
        } else {
            // 发送服务器消息获取背包信息
        }

        RedPointSys.notify(RedPointEvent.NOTIFY_ACTIVE,true);
    }

    /**
     * 获取背包数据
     * @returns 
     */
    public get containers():Item[]{ return this._sort(); }

    /**
     * 获取背包中某个道具得数量
     * @param id 
     * @returns 
     */
    public getCount(id:number):number{
        let count:number = 0;
        for (let it of this._items){
            if (it.id === id) count += it.count;
        }
        return count;
    }

    /**
     * 添加物品
     * @param array 
     * @returns 
     */
    public addItem(array:Item[]):boolean{
        if (App.Util.isInvalid(array) || array.length < 1) return false;
        let tmpArr:Item[] = [];
        const find = (item:Item)=>{
            for (let it of tmpArr){
                if (it.id === item.id){
                    it.count += item.count;
                    return ;
                }
            }
            tmpArr.push(item);
        };
        for (let it of array) find(it);

        this._sort();
        while (tmpArr.length > 0){
            const it = tmpArr.shift();
            const cfg:PropAttribute = PropSys.getAttributeByID(it.id);       
            if (cfg.maxAdd < 0){
                this._add(it.id,it.count,INFINITE);
                continue ;
            }   
            let groups = Math.floor(it.count/cfg.maxAdd);
            for (let i = 0; i < groups; ++i) this._add(it.id, cfg.maxAdd,cfg.maxAdd);
            const remainder = Math.floor(it.count%cfg.maxAdd);
            remainder > 0 && this._add(it.id,remainder,cfg.maxAdd);
        }

        return true ;
    }

    /**
     * 删除物品
     * @param array 
     * @returns 
     */
    public delItem(array:Item[]):boolean{
        let tmpArr:Item[] = [];
        const find = (item:Item)=>{
            for (let it of tmpArr){
                if (it.id === item.id){
                    it.count += item.count;
                    return ;
                }
            }
            tmpArr.push(item);
        };
        for (let it of array) find(it);
        
        this._sort();
        while (tmpArr.length > 0){
            const it = tmpArr.shift();
            const cfg:PropAttribute = PropSys.getAttributeByID(it.id);            
            let groups = Math.floor(it.count/cfg.maxAdd);
            for (let i = 0; i < groups; ++i) this._delete(it.id,cfg.maxAdd);
            this._delete(it.id,Math.floor(it.count%cfg.maxAdd));
        }

        return true;
    }

    public useProp(id:number, useCount:number, cb:(flag:UsePropResult,goods:any)=>void){
        if (this.getCount(id) < useCount ){
            cb && cb(UsePropResult.fail,null);
            return ;
        }

        const cfg = PropSys.getAttributeByID(id);
        if (App.Util.isInvalid(cfg)){
            cc.warn(`PropSys.useProp(invalid item ID=${id})`);
            return ;
        }
        const useCall = (res:UsePropResult)=>{
            res === UsePropResult.success && this._sort();
            cb && cb(res,this._items);
        };
        switch (cfg.type){
            case PropType.routine:useCall(this._routineType(cfg,useCount),);break; // 常规类
            case PropType.ticket:useCall(this._ticketType(cfg,useCount));break; // 票券类
            case PropType.gift:useCall(this._giftType(cfg,useCount));break; // 礼包类
            case PropType.interactive:useCall(this._interactiveType(cfg,useCount));break; // 交互类
            case PropType.game:useCall(this._gameType(cfg,useCount));break; // 游戏类
            case PropType.decorate:useCall(this._decorateType(cfg,useCount));break; // 妆扮类
            case PropType.debris:useCall(this._debrisType(cfg,useCount));break; // 合成类道具

            default : {
                cc.log(`PropSys.useProp(id=${id}) prop type abnormal.`);
                App.popTips(App.getText('prop.invalid'));
                useCall(UsePropResult.fail);
                return ;
            }
        }
    }
    /**
     * 是否可增加或者删除某种道具
     * @param id 
     * @param count 
     * @param isAdd 
     * @returns 
     */
    private _isCan(id:number,count:number,isAdd:boolean):boolean{
        const cfg:PropAttribute = PropSys.getAttributeByID(id);
        if (App.Util.isInvalid(cfg) || count < 1) return false;

        if (cfg.maxAdd < 0 && this._getEmpty() > 0){ return true ;}

        let num = 0;
        let tmpArr = this._items.slice(0);
        for (let i = tmpArr.length - 1; i >= 0; --i){
            if (tmpArr[i].id === id){
                num += tmpArr[i].count;
                tmpArr.splice(i,1);
            }
        }
        if (isAdd){
            let groups = Math.ceil((num+count)/cfg.maxAdd);
            const empty = MAX_CONTAINERS-tmpArr.length;
            return groups <= empty;
        } else {
            return num >= count;
        }
    }

    /**
     * 背包空格
     * @returns 
     */
    private _getEmpty():number{ return MAX_CONTAINERS-this._items.length;}

    /**
     * 往背包添加指定数量的物品
     * @param id 
     * @param count 
     * @param max 
     * @returns 
     */
    private _add(id:number,count:number,max:number):boolean{
        if (this._getEmpty() < 1 || count < 1 || max < 1) return ;

        if (count === max){
            this._items.push({id:id,count:max});
            return ;
        }
        let remainder = count;
        for (let tmp of this._items){
            if (tmp.id === id && tmp.count < max){
                if ((tmp.count + count) < max) {
                    tmp.count += count;
                } else {
                    remainder -= (max - tmp.count);
                    remainder > 0 && this._items.push({id:id,count:remainder});
                    tmp.count = max;
                }
                return ;
            }
        }
        remainder > 0 && this._items.push({id:id,count:remainder});
    }

    /**
     * 删除给定数量的某种道具
     * @param id 
     * @param count 
     * @returns 
     */
    private _delete(id:number,count:number):boolean{
        if (this.getCount(id) < count) return false;

        for (let i = 0; i < this._items.length; ++i){
            const tmp = this._items[i];
            if (tmp.id === id){
                if (tmp.count >= count){
                    this._items[i].count -= count;
                    this._items[i].count  === 0 && this._items.splice(i,1);
                    return true;
                } else if (this._items[i-1].id === id) {
                    const num = tmp.count;
                    this._items.splice(i,1);
                    this._items[i-1].count -= (count-num);
                    return true; 
                }
            }
        }

        return false;
    }

    private _sort():Item[]{
        if (!this._items) return ;
        return this._items.sort((a,b)=>{
            return a.id === b.id ? b.count-a.count : a.id-b.id;
        });
    }

    /**
     * 常规类道具
     * @param cfg 
     * @returns 
     */
    private _routineType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }

    /**
     * 票券类
     * @param cfg 
     * @returns 
     */
    private _ticketType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }

    /**
     * 礼包类
     * @param cfg 
     * @returns 
     */
    private _giftType(cfg:PropAttribute, useCount:number):UsePropResult{
        let array:{id:number,count:number}[] = [];
        for (let it of cfg.gifts){
            if (!this._isCan(it.id,it.count,true)){
                return UsePropResult.fail;
            }
            array.push({id:it.id,count:it.count});
        }
        return (this.delItem([{id:cfg.id,count:useCount}]) && this.addItem(array))? UsePropResult.success:UsePropResult.fail;
    }

    /**
     * 社交类
     * @param cfg 
     * @returns 
     */
    private _interactiveType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }

    /**
     * 游戏类
     * @param cfg 
     * @returns 
     */
    private _gameType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }

    /**
     * 装扮类
     * @param cfg 
     * @returns 
     */
    private _decorateType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }

    /**
     * 合成类
     * @param cfg 
     * @returns 
     */
    private _debrisType(cfg:PropAttribute, useCount:number):UsePropResult{
        return UsePropResult.fail;
    }
}

const PackSys:CPackSys = CPackSys.getInstance<CPackSys>(CPackSys);
export default PackSys;